<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="utf-8">
		<title>libora.js examples</title>
		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
		<link rel="shortcut icon" href="../files/favicon_white.ico" media="(prefers-color-scheme: dark)"/>
		<link rel="shortcut icon" href="../files/favicon.ico" media="(prefers-color-scheme: light)" />
		<link rel="stylesheet" type="text/css" href="../files/main.css">
	</head>
	<body>

		<div id="panel">

			<div id="header">
				<h1><a href="https://threejs.org">libora.js</a></h1>

				<div id="sections">
					<a href="../docs/index.html#manual/introduction/Creating-a-scene">docs</a>
					<span class="selected">examples</span>
				</div>

				<div id="expandButton"></div>
			</div>

			<div id="panelScrim"></div>

			<div id="contentWrapper">

				<div id="inputWrapper">
					<input placeholder="" type="text" id="filterInput" autocorrect="off" autocapitalize="off" spellcheck="false" />
					<div id="clearSearchButton"></div>
				</div>

				<div id="content">
					<img id="previewsToggler" src="./files/thumbnails.svg" width="20" height="20" />
				</div>
			</div>

		</div>

		<iframe id="viewer" name="viewer" allow="fullscreen; xr-spatial-tracking;"></iframe>

		<a id="button" target="_blank"><img src="../files/ic_code_black_24dp.svg"></a>

		<script>

		const panel = document.getElementById( 'panel' );
		const content = document.getElementById( 'content' );
		const viewer = document.getElementById( 'viewer' );
		const filterInput = document.getElementById( 'filterInput' );
		const clearSearchButton = document.getElementById( 'clearSearchButton' );
		const expandButton = document.getElementById( 'expandButton' );
		const viewSrcButton = document.getElementById( 'button' );
		const panelScrim = document.getElementById( 'panelScrim' );
		const previewsToggler = document.getElementById( 'previewsToggler' );

		const sectionLink = document.querySelector( '#sections > a' );
		const sectionDefaultHref = sectionLink.href;

		const links = {};
		const validRedirects = new Map();
		const container = document.createElement( 'div' );

		let selected = null;

		init();

		async function init() {

			content.appendChild( container );

			viewSrcButton.style.display = 'none';

			const files = await ( await fetch( 'files.json' ) ).json();
			const tags = await ( await fetch( 'tags.json' ) ).json();

			for ( const key in files ) {

				const category = files[ key ];

				const header = document.createElement( 'h2' );
				header.textContent = key;
				header.setAttribute( 'data-category', key );
				container.appendChild( header );

				for ( let i = 0; i < category.length; i ++ ) {

					const file = category[ i ];

					const link = createLink( file, tags[ file ] );
					container.appendChild( link );

					links[ file ] = link;
					const names = file.split("_");
					validRedirects.set( file, `${names[0]}/${names[1]}` + '.html' );

				}

			}

			if ( window.location.hash !== '' ) {

				const file = window.location.hash.substring( 1 );

				// use a predefined map of redirects to avoid untrusted URL redirection due to user-provided value

				if ( validRedirects.has( file ) === true ) {

					selectFile( file );
					viewer.src = validRedirects.get( file );
					viewer.style.display = 'unset';

				}

			}

			if ( viewer.src === '' ) {

				viewer.srcdoc = document.getElementById( 'PlaceholderHTML' ).innerHTML;
				viewer.style.display = 'unset';

			}

			filterInput.value = extractQuery();

			if ( filterInput.value !== '' ) {

				panel.classList.add( 'searchFocused' );

				updateFilter( files, tags );

			} else {

				updateLink( '' );

			}

			// Events

			filterInput.onfocus = function ( ) {

				panel.classList.add( 'searchFocused' );

			};

			filterInput.onblur = function ( ) {

				if ( filterInput.value === '' ) {

					panel.classList.remove( 'searchFocused' );

				}

			};

			clearSearchButton.onclick = function ( ) {

				filterInput.value = '';
				updateFilter( files, tags );
				filterInput.focus();

			};

			filterInput.addEventListener( 'input', function () {

				updateFilter( files, tags );

			} );


			expandButton.addEventListener( 'click', function ( event ) {

				event.preventDefault();
				panel.classList.toggle( 'open' );

			} );

			panelScrim.onclick = function ( event ) {

				event.preventDefault();
				panel.classList.toggle( 'open' );

			};

			previewsToggler.onclick = function ( event ) {

				event.preventDefault();
				content.classList.toggle( 'minimal' );

			};

			// iOS iframe auto-resize workaround

			if ( /(iPad|iPhone|iPod)/g.test( navigator.userAgent ) ) {

				viewer.style.width = getComputedStyle( viewer ).width;
				viewer.style.height = getComputedStyle( viewer ).height;
				viewer.setAttribute( 'scrolling', 'no' );

			}

		}

		function createLink( file, tags ) {

			const external = Array.isArray( tags ) && tags.includes( 'external' ) ? ' <span class="tag">external</span>' : '';

			const names = file.split("_")
			const template = `
				<div class="card">
					<a href="${ names[0] }/${names[1]}.html" target="viewer">
						<div class="cover">
							<img src="screenshots/${ file }.png" loading="lazy" width="400" />
						</div>
						<div class="title">${ getName( file ) }${ external }</div>
					</a>
				</div>
			`;

			const link = createElementFromHTML( template );

			link.querySelector( 'a[target="viewer"]' ).addEventListener( 'click', function ( event ) {

				if ( event.button !== 0 || event.ctrlKey || event.altKey || event.metaKey ) return;

				selectFile( file );

			} );

			return link;

		}

		function selectFile( file ) {

			if ( selected !== null ) links[ selected ].classList.remove( 'selected' );

			links[ file ].classList.add( 'selected' );

			window.location.hash = file;
			viewer.focus();
			viewer.style.display = 'unset';

			panel.classList.remove( 'open' );

			selected = file;

			// Reveal "View source" button and set attributes to this example
			viewSrcButton.style.display = '';
			viewSrcButton.href = 'https://github.com/mrdoob/three.js/blob/master/examples/' + selected + '.html';
			viewSrcButton.title = 'View source code for ' + getName( selected ) + ' on GitHub';

		}

		function escapeRegExp( string ) {

			return string.replace( /[.*+?^${}()|[\]\\]/g, '\\$&' ); // https://stackoverflow.com/a/6969486/5250847

		}

		function updateFilter( files, tags ) {

			let v = filterInput.value.trim();
			v = v.replace( /\s+/gi, ' ' ); // replace multiple whitespaces with a single one

			if ( v !== '' ) {

				window.history.replaceState( {}, '', '?q=' + v + window.location.hash );

			} else {

				window.history.replaceState( {}, '', window.location.pathname + window.location.hash );

			}

			const exp = new RegExp( escapeRegExp( v ), 'gi' );

			for ( const key in files ) {

				const section = files[ key ];

				for ( let i = 0; i < section.length; i ++ ) {

					filterExample( section[ i ], exp, tags );

				}

			}

			layoutList( files );

			updateLink( v );

		}

		function updateLink( search ) {

			// update docs link

			if ( search ) {

				const link = sectionLink.href.split( /[?#]/ )[ 0 ];
				sectionLink.href = `${link}?q=${search}`;

			} else {

				sectionLink.href = sectionDefaultHref;

			}

		}

		function filterExample( file, exp, tags ) {

			const link = links[ file ];
			if ( file in tags ) file += ' ' + tags[ file ].join( ' ' );
			const res = file.replace( /_+/g, ' ' ).match( exp );

			if ( res && res.length > 0 ) {

				link.classList.remove( 'hidden' );

			} else {

				link.classList.add( 'hidden' );

			}

		}

		function getName( file ) {

			const name = file.split( '_' );
			name.shift();
			return name.join( ' / ' );

		}

		function layoutList( files ) {

			for ( const key in files ) {

				let collapsed = true;

				const section = files[ key ];

				for ( let i = 0; i < section.length; i ++ ) {

					const file = section[ i ];

					if ( links[ file ].classList.contains( 'hidden' ) === false ) {

						collapsed = false;
						break;

					}

				}

				const element = document.querySelector( 'h2[data-category="' + key + '"]' );

				if ( collapsed ) {

					element.classList.add( 'hidden' );

				} else {

					element.classList.remove( 'hidden' );

				}

			}

		}

		function extractQuery() {

			const search = window.location.search;

			if ( search.indexOf( '?q=' ) !== - 1 ) {

				return decodeURI( search.slice( 3 ) );

			}

			return '';

		}

		function createElementFromHTML( htmlString ) {

			const div = document.createElement( 'div' );
			div.innerHTML = htmlString.trim();
			return div.firstChild;

		}

		</script>
		<template id="PlaceholderHTML">
			<!DOCTYPE html>
				<html lang="en">
					<head>
						<meta charset="utf-8">
						<title>three.js examples</title>
						<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
						<link rel="stylesheet" type="text/css" href="../files/main.css">
						<style>
						html, body {
							height: 100%;
						}
						body {
							height: 100%;
							display: flex;
							align-items: center;
							justify-content: center;
							user-select: none;
						}
						</style>
					</head>
					<body>
						Select an example from the sidebar
					</body>
				</html>
		</template>
	</body>
</html>
